#include "Parameter.hpp"
#include <GL/gl.h>
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstdlib>

void UserParameter::init()
{
	facefront = GL_CCW;
	for(int i = 0;i<3;i++){
		color[i]=255;
		rotation[i]=0;
		translation[i]=0;
	}
	nearer = 0.1;
	farer = 6;
	primitive = GL_LINE;
	rotated = false;
}

void UserParameter::reset()
{
	settrans(0,0,0);
	setrotat(0,0,0);
	setrotat(0,0,0);
	//setclip(nearmin,farmax);
}

void UserParameter::setstruct(bool clockwise, char view)
{
	if(clockwise==TRUE){
		facefront =GL_CW;
		std::cout << "Clockwise: " << clockwise << '\t' << "View: ";
	}
	else
		facefront = GL_CCW;
	switch(view){
	case 'p':
		primitive = GL_POINT;
		std::cout << "Point" << std::endl;
		break;
	case 'f':
		primitive = GL_LINE;
		std::cout << "Frame" << std::endl;
		break;
	case 's':
		primitive = GL_FILL;
		std::cout << "Solid" << std::endl;
		break;
	default:  std::cout << "Unknown" << std::endl; break;
	}
	emit refresh();
}

void UserParameter::setcolor(int red, int green, int blue)
{
	color[0]=red;
	color[1]=green;
	color[2]=blue;
	std::cout << "Color: " << red << ", " << green << ", " << blue << std::endl;
	emit refresh();
}

void UserParameter::settrans(float x, float y, float z)
{
	translation[0]=x;
	translation[1]=y;
	translation[2]=z;
	std::cout << "Translation: " << x << ", " << y << ", " << z << std::endl;
	emit refresh();
}

void UserParameter::setrotat(float x, float y, float z)
{
	rotationold[0] = rotation[0];
	rotationold[1] = rotation[1];
	rotationold[2] = rotation[2];
	rotation[0] = x;
	rotation[1] = y;
	rotation[2] = z;
	std::cout << "Rotation: " << x << ", " << y << ", " << z << std::endl;
	rotated = true;
	emit refresh();
	rotated = false;
}

void UserParameter::setclip(float n, float f)
{
	nearer = n;
	farer = f;
	std::cout << "Near: " << n << '\t' << "Far" << f << std::endl;
	emit refresh();
}

inline float fmax(float x, float y)
{
	return x>y?x:y;
}

inline float fmin(float x, float y)
{
	return x<y?x:y;
}

void InputParameter::readfile(const char *FileName)
{
	char ch;
	FILE* fp = fopen(FileName,"r");
	if (fp==NULL)
	{
		printf("ERROR: unable to open TriObj [%s]!\n",FileName);
		exit(1);
	}
	fscanf(fp, "%c", &ch);
	while(ch!= '\n') // skip the first line
		fscanf(fp, "%c", &ch);

	fscanf(fp,"# triangles = %d\n", &trinum); // read # of triangles
	fscanf(fp,"Material count = %d\n", &marnum); // read material count
	//
	mat.resize(marnum);
	for(int i=0; i<marnum; i++)
	{
		fscanf(fp, "ambient color %f %f %f\n", &mat[i].acolor[0], &mat[i].acolor[1], &mat[i].acolor[2]);
		fscanf(fp, "diffuse color %f %f %f\n", &mat[i].dcolor[0], &mat[i].dcolor[1], &mat[i].dcolor[2]);
		fscanf(fp, "specular color %f %f %f\n", &mat[i].scolor[0], &mat[i].scolor[1], &mat[i].scolor[2]);
		fscanf(fp, "material shine %f\n", &mat[i].shine);
	}
	//
	fscanf(fp, "%c", &ch);
	while(ch!= '\n') // skip documentation line
		fscanf(fp, "%c", &ch);

	printf ("Reading in %s (%d triangles). . .\n", FileName, trinum);

	tri.resize(trinum);
	for (int i=0; i<trinum; i++) // read triangles
	{
		for (int j=0;j<3;j++)
		{

			fscanf(fp, "v%c %f %f %f %f %f %f %d\n", &ch,
				   &(tri[i].v[j].pos[0]), &(tri[i].v[j].pos[1]), &(tri[i].v[j].pos[2]),
				   &(tri[i].v[j].norm[0]), &(tri[i].v[j].norm[1]), &(tri[i].v[j].norm[2]),
				   &(tri[i].v[j].matind));
			tri[i].color[j] =(unsigned char)(int)(255*(mat[tri[i].v[0].matind].dcolor[j]));//Since very vertex use the same material index, so here I take the first vertex as its color
		}
		fscanf(fp, "face normal %f %f %f\n", &(tri[i].fnorm[0]), &(tri[i].fnorm[1]),
			   &(tri[i].fnorm[2]));
	}
	// get the max and min of the object in x y z
	for(int i = 0; i < 3; i++)
		pmax[i] = pmin[i] = tri[0].v[0].pos[i];
	for(int i = 0; i < trinum; i++)
	{
		for(int j = 0; j < 3; j++)
		{
			for(int k = 0; k < 3; k++)
			{
				if(tri[i].v[j].pos[k] < pmin[k])
					pmin[k] = tri[i].v[j].pos[k];
				else if(tri[i].v[j].pos[k] > pmax[k])
					pmax[k] = tri[i].v[j].pos[k];
			}
		}
	}

	distance = fmax(pmax[1] - pmin[1],pmax[0] - pmin[0])* sqrt(3.0);
	float translate_scaler[3];
	translate_scaler[0] = fmin(fmin(pmax[0] - pmin[0],pmax[1] - pmin[1]),pmax[2] -pmin[2]);
	translate_scaler[1] = translate_scaler[0];
	translate_scaler[2] = translate_scaler[0];
	float nearer_scaler = distance;
	float farer_scaler = distance;
	fclose(fp);
	emit initpara(-10*translate_scaler[0], 10*translate_scaler[0], -10*translate_scaler[1], 10*translate_scaler[1], -10*translate_scaler[2], 10*translate_scaler[2], 0.1*nearer_scaler, 5*farer_scaler);
	emit reset();
}
